home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / bartool.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  42.7 KB  |  1,610 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #if !defined(_WIN32_WCE_NO_CONTROLBARS)
  13.  
  14. #ifdef AFX_CORE3_SEG
  15. #pragma code_seg(AFX_CORE3_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define new DEBUG_NEW
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CToolBar creation etc
  27.  
  28. #ifdef AFX_CORE3_SEG
  29. #pragma code_seg(AFX_CORE3_SEG)
  30. #endif
  31.  
  32. #if !defined(_WIN32_WCE)
  33. /*
  34.     DIBs use RGBQUAD format:
  35.         0xbb 0xgg 0xrr 0x00
  36.  
  37.     Reasonably efficient code to convert a COLORREF into an
  38.     RGBQUAD is byte-order-dependent, so we need different
  39.     code depending on the byte order we're targeting.
  40. */
  41. #define RGB_TO_RGBQUAD(r,g,b)   (RGB(b,g,r))
  42. #define CLR_TO_RGBQUAD(clr)     (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))
  43.  
  44. struct AFX_COLORMAP
  45. {
  46.     // use DWORD instead of RGBQUAD so we can compare two RGBQUADs easily
  47.     DWORD rgbqFrom;
  48.     int iSysColorTo;
  49. };
  50.  
  51. AFX_STATIC_DATA const AFX_COLORMAP _afxSysColorMap[] =
  52. {
  53.     // mapping from color in DIB to system color
  54.     { RGB_TO_RGBQUAD(0x00, 0x00, 0x00),  COLOR_BTNTEXT },       // black
  55.     { RGB_TO_RGBQUAD(0x80, 0x80, 0x80),  COLOR_BTNSHADOW },     // dark gray
  56.     { RGB_TO_RGBQUAD(0xC0, 0xC0, 0xC0),  COLOR_BTNFACE },       // bright gray
  57.     { RGB_TO_RGBQUAD(0xFF, 0xFF, 0xFF),  COLOR_BTNHIGHLIGHT }   // white
  58. };
  59.  
  60. HBITMAP AFXAPI
  61. AfxLoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc, BOOL bMono)
  62. {
  63.     HGLOBAL hglb;
  64.     if ((hglb = LoadResource(hInst, hRsrc)) == NULL)
  65.         return NULL;
  66.  
  67.     LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
  68.     if (lpBitmap == NULL)
  69.         return NULL;
  70.  
  71.     // make copy of BITMAPINFOHEADER so we can modify the color table
  72.     const int nColorTableSize = 16;
  73.     UINT nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
  74.     LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)::malloc(nSize);
  75.     if (lpBitmapInfo == NULL)
  76.         return NULL;
  77.     memcpy(lpBitmapInfo, lpBitmap, nSize);
  78.  
  79.     // color table is in RGBQUAD DIB format
  80.     DWORD* pColorTable =
  81.         (DWORD*)(((LPBYTE)lpBitmapInfo) + (UINT)lpBitmapInfo->biSize);
  82.  
  83.     for (int iColor = 0; iColor < nColorTableSize; iColor++)
  84.     {
  85.         // look for matching RGBQUAD color in original
  86.         for (int i = 0; i < _countof(_afxSysColorMap); i++)
  87.         {
  88.             if (pColorTable[iColor] == _afxSysColorMap[i].rgbqFrom)
  89.             {
  90.                 if (bMono)
  91.                 {
  92.                     // all colors except text become white
  93.                     if (_afxSysColorMap[i].iSysColorTo != COLOR_BTNTEXT)
  94.                         pColorTable[iColor] = RGB_TO_RGBQUAD(255, 255, 255);
  95.                 }
  96.                 else
  97.                     pColorTable[iColor] =
  98.                         CLR_TO_RGBQUAD(::GetSysColor(_afxSysColorMap[i].iSysColorTo));
  99.                 break;
  100.             }
  101.         }
  102.     }
  103.  
  104.     int nWidth = (int)lpBitmapInfo->biWidth;
  105.     int nHeight = (int)lpBitmapInfo->biHeight;
  106.     HDC hDCScreen = ::GetDC(NULL);
  107.     HBITMAP hbm = ::CreateCompatibleBitmap(hDCScreen, nWidth, nHeight);
  108.  
  109.     if (hbm != NULL)
  110.     {
  111.         HDC hDCGlyphs = ::CreateCompatibleDC(hDCScreen);
  112.         HBITMAP hbmOld = (HBITMAP)::SelectObject(hDCGlyphs, hbm);
  113.  
  114.         LPBYTE lpBits;
  115.         lpBits = (LPBYTE)(lpBitmap + 1);
  116.         lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
  117.  
  118.         StretchDIBits(hDCGlyphs, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
  119.             lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
  120.         SelectObject(hDCGlyphs, hbmOld);
  121.         ::DeleteDC(hDCGlyphs);
  122.     }
  123.     ::ReleaseDC(NULL, hDCScreen);
  124.  
  125.     // free copy of bitmap info struct and resource itself
  126.     ::free(lpBitmapInfo);
  127.     ::FreeResource(hglb);
  128.  
  129.     return hbm;
  130. }
  131.  
  132. #ifdef AFX_INIT_SEG
  133. #pragma code_seg(AFX_INIT_SEG)
  134. #endif
  135.  
  136. struct AFX_DLLVERSIONINFO
  137. {
  138.         DWORD cbSize;
  139.         DWORD dwMajorVersion;                   // Major version
  140.         DWORD dwMinorVersion;                   // Minor version
  141.         DWORD dwBuildNumber;                    // Build number
  142.         DWORD dwPlatformID;                     // DLLVER_PLATFORM_*
  143. };
  144.  
  145. typedef HRESULT (CALLBACK* AFX_DLLGETVERSIONPROC)(AFX_DLLVERSIONINFO *);
  146.  
  147. int _afxComCtlVersion = -1;
  148.  
  149. DWORD AFXAPI _AfxGetComCtlVersion()
  150. {
  151.     // return cached version if already determined...
  152.     if (_afxComCtlVersion != -1)
  153.         return _afxComCtlVersion;
  154.  
  155.     // otherwise determine comctl32.dll version via DllGetVersion
  156.     HINSTANCE hInst = ::GetModuleHandleA("COMCTL32.DLL");
  157.     ASSERT(hInst != NULL);
  158.     AFX_DLLGETVERSIONPROC pfn;
  159.     pfn = (AFX_DLLGETVERSIONPROC)GetProcAddress(hInst, "DllGetVersion");
  160.     DWORD dwVersion = VERSION_WIN4;
  161.     if (pfn != NULL)
  162.     {
  163.         AFX_DLLVERSIONINFO dvi;
  164.         memset(&dvi, 0, sizeof(dvi));
  165.         dvi.cbSize = sizeof(dvi);
  166.         HRESULT hr = (*pfn)(&dvi);
  167.         if (SUCCEEDED(hr))
  168.         {
  169.             ASSERT(dvi.dwMajorVersion <= 0xFFFF);
  170.             ASSERT(dvi.dwMinorVersion <= 0xFFFF);
  171.             dwVersion = MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);
  172.         }
  173.     }
  174.     _afxComCtlVersion = dwVersion;
  175.     return dwVersion;
  176. }
  177.  
  178. int _afxDropDownWidth = -1;
  179.  
  180. int AFXAPI _AfxGetDropDownWidth()
  181. {
  182.     // return cached version if already determined...
  183.     if (_afxDropDownWidth != -1)
  184.         return _afxDropDownWidth;
  185.  
  186.     // otherwise calculate it...
  187.     HDC hDC = GetDC(NULL);
  188.     ASSERT(hDC != NULL);
  189.     HFONT hFont;
  190.     if ((hFont = CreateFont(GetSystemMetrics(SM_CYMENUCHECK), 0, 0, 0, 
  191.         FW_NORMAL, 0, 0, 0, SYMBOL_CHARSET, 0, 0, 0, 0, _T("Marlett"))) != NULL)
  192.         hFont = (HFONT)SelectObject(hDC, hFont);
  193.     VERIFY(GetCharWidth(hDC, '6', '6', &_afxDropDownWidth));
  194.     if (hFont != NULL)
  195.     {
  196.         SelectObject(hDC, hFont);
  197.         DeleteObject(hFont);
  198.     }
  199.     ReleaseDC(NULL, hDC);
  200.     ASSERT(_afxDropDownWidth != -1);
  201.     return _afxDropDownWidth;
  202. }
  203. #endif // _WIN32_WCE
  204.  
  205. CToolBar::CToolBar()
  206. {
  207.     // initialize state
  208.     m_pStringMap = NULL;
  209.     m_hRsrcImageWell = NULL;
  210.     m_hInstImageWell = NULL;
  211.     m_hbmImageWell = NULL;
  212.     m_bDelayedButtonLayout = TRUE;
  213. #if defined(_WIN32_WCE)
  214.     m_pWndCommandBar = NULL;
  215. #endif // _WIN32_WCE
  216.  
  217.     // default image sizes
  218.     m_sizeImage.cx = 16;
  219.     m_sizeImage.cy = 15;
  220.  
  221.     // default button sizes
  222.     m_sizeButton.cx = 23;
  223.     m_sizeButton.cy = 22;
  224.  
  225.     // top and bottom borders are 1 larger than default for ease of grabbing
  226. #if defined(_WIN32_WCE)
  227.     m_cyTopBorder = 0;
  228.     m_cyBottomBorder = 2;
  229. #else // _WIN32_WCE
  230.     m_cyTopBorder = 3;
  231.     m_cyBottomBorder = 3;
  232. #endif // _WIN32_WCE
  233. }
  234.  
  235. CToolBar::~CToolBar()
  236. {
  237.     AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell);
  238.     delete m_pStringMap;
  239.  
  240.     m_nCount = 0;
  241. }
  242.  
  243. BOOL CToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
  244. {
  245.     return CreateEx(pParentWnd, 0, dwStyle, 
  246.         CRect(m_cxLeftBorder, m_cyTopBorder, m_cxRightBorder, m_cyBottomBorder), nID);
  247. }
  248.  
  249. BOOL CToolBar::CreateEx(CWnd* pParentWnd, DWORD dwCtrlStyle, DWORD dwStyle, CRect rcBorders, UINT nID)
  250. {
  251.     ASSERT_VALID(pParentWnd);   // must have a parent
  252.     ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC)));
  253.  
  254. #if defined(_WIN32_WCE)
  255. // WinCE: default to fixed size toolbars so we get wrapping without asking for it
  256.     if(!(dwStyle & CBRS_SIZE_DYNAMIC))
  257.         dwStyle |= CBRS_SIZE_FIXED; // default to wrapped toolbars
  258. #endif // _WIN32_WCE
  259.     SetBorders(rcBorders);
  260.  
  261.     // save the style
  262.     m_dwStyle = (dwStyle & CBRS_ALL);
  263.     if (nID == AFX_IDW_TOOLBAR)
  264.         m_dwStyle |= CBRS_HIDE_INPLACE;
  265.  
  266.     dwStyle &= ~CBRS_ALL;
  267.     dwStyle |= CCS_NOPARENTALIGN|CCS_NOMOVEY|CCS_NODIVIDER|CCS_NORESIZE;
  268.     dwStyle |= dwCtrlStyle;
  269.  
  270.     // initialize common controls
  271.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_BAR_REG));
  272. #if !defined(_WIN32_WCE)
  273.     _AfxGetComCtlVersion();
  274.     ASSERT(_afxComCtlVersion != -1);
  275.     _AfxGetDropDownWidth();
  276.     ASSERT(_afxDropDownWidth != -1);
  277. #endif // _WIN32_WCE
  278.  
  279.     // create the HWND
  280.     CRect rect; rect.SetRectEmpty();
  281.     if (!CWnd::Create(TOOLBARCLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
  282.         return FALSE;
  283.  
  284.     // sync up the sizes
  285.     SetSizes(m_sizeButton, m_sizeImage);
  286.  
  287.     // Note: Parent must resize itself for control bar to be resized
  288.  
  289.     return TRUE;
  290. }
  291.  
  292. /////////////////////////////////////////////////////////////////////////////
  293. // CToolBar
  294.  
  295. #if !defined(_WIN32_WCE)
  296. BOOL CToolBar::OnNcCreate(LPCREATESTRUCT lpCreateStruct)
  297. {
  298.     if (!CControlBar::OnNcCreate(lpCreateStruct))
  299.         return FALSE;
  300.  
  301.     // if the owner was set before the toolbar was created, set it now
  302.     if (m_hWndOwner != NULL)
  303.         DefWindowProc(TB_SETPARENT, (WPARAM)m_hWndOwner, 0);
  304.  
  305.     DefWindowProc(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
  306.     return TRUE;
  307. }
  308. #endif // _WIN32_WCE
  309.  
  310. void CToolBar::SetOwner(CWnd* pOwnerWnd)
  311. {
  312.     ASSERT_VALID(this);
  313.     if (m_hWnd != NULL)
  314.     {
  315.         ASSERT(::IsWindow(m_hWnd));
  316.         DefWindowProc(TB_SETPARENT, (WPARAM)pOwnerWnd->GetSafeHwnd(), 0);
  317.     }
  318.     CControlBar::SetOwner(pOwnerWnd);
  319. }
  320.  
  321. void CToolBar::SetSizes(SIZE sizeButton, SIZE sizeImage)
  322. {
  323.     ASSERT_VALID(this);
  324.  
  325.     // sizes must be non-zero and positive
  326.     ASSERT(sizeButton.cx > 0 && sizeButton.cy > 0);
  327.     ASSERT(sizeImage.cx > 0 && sizeImage.cy > 0);
  328.  
  329.     // button must be big enough to hold image
  330.     //   + 7 pixels on x
  331.     //   + 6 pixels on y
  332.     ASSERT(sizeButton.cx >= sizeImage.cx + 7);
  333.     ASSERT(sizeButton.cy >= sizeImage.cy + 6);
  334.  
  335.     if (::IsWindow(m_hWnd))
  336.     {
  337.         // set the sizes via TB_SETBITMAPSIZE and TB_SETBUTTONSIZE
  338.         VERIFY(SendMessage(TB_SETBITMAPSIZE, 0, MAKELONG(sizeImage.cx, sizeImage.cy)));
  339.         VERIFY(SendMessage(TB_SETBUTTONSIZE, 0, MAKELONG(sizeButton.cx, sizeButton.cy)));
  340. #if defined(_WIN32_WCE)
  341. // WinCE: Make up for no WM_NCCREATE
  342.     if (m_hWndOwner != NULL)
  343.         DefWindowProc(TB_SETPARENT, (WPARAM)m_hWndOwner, 0);
  344.     DefWindowProc(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
  345. #endif // _WIN32_WCE
  346.         Invalidate();   // just to be nice if called when toolbar is visible
  347.     }
  348.     else
  349.     {
  350.         // just set our internal values for later
  351.         m_sizeButton = sizeButton;
  352.         m_sizeImage = sizeImage;
  353.     }
  354. }
  355.  
  356. void CToolBar::SetHeight(int cyHeight)
  357. {
  358.     ASSERT_VALID(this);
  359.  
  360.     int nHeight = cyHeight;
  361.     if (m_dwStyle & CBRS_BORDER_TOP)
  362.         cyHeight -= afxData.cyBorder2;
  363.     if (m_dwStyle & CBRS_BORDER_BOTTOM)
  364.         cyHeight -= afxData.cyBorder2;
  365.     m_cyBottomBorder = (cyHeight - m_sizeButton.cy) / 2;
  366.     // if there is an extra pixel, m_cyTopBorder will get it
  367.     m_cyTopBorder = cyHeight - m_sizeButton.cy - m_cyBottomBorder;
  368.     if (m_cyTopBorder < 0)
  369.     {
  370.         TRACE1("Warning: CToolBar::SetHeight(%d) is smaller than button.\n",
  371.             nHeight);
  372.         m_cyBottomBorder += m_cyTopBorder;
  373.         m_cyTopBorder = 0;  // will clip at bottom
  374.     }
  375.  
  376.     // recalculate the non-client region
  377.     SetWindowPos(NULL, 0, 0, 0, 0,
  378.         SWP_DRAWFRAME|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER);
  379.     Invalidate();   // just to be nice if called when toolbar is visible
  380. }
  381.  
  382. struct CToolBarData
  383. {
  384.     WORD wVersion;
  385.     WORD wWidth;
  386.     WORD wHeight;
  387.     WORD wItemCount;
  388.     //WORD aItems[wItemCount]
  389.  
  390.     WORD* items()
  391.         { return (WORD*)(this+1); }
  392. };
  393.  
  394. BOOL CToolBar::LoadToolBar(LPCTSTR lpszResourceName)
  395. {
  396.     ASSERT_VALID(this);
  397.     ASSERT(lpszResourceName != NULL);
  398.  
  399.     // determine location of the bitmap in resource fork
  400.     HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_TOOLBAR);
  401.     HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_TOOLBAR);
  402.     if (hRsrc == NULL)
  403.         return FALSE;
  404.  
  405.     HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
  406.     if (hGlobal == NULL)
  407.         return FALSE;
  408.  
  409.     CToolBarData* pData = (CToolBarData*)LockResource(hGlobal);
  410.     if (pData == NULL)
  411.         return FALSE;
  412.     ASSERT(pData->wVersion == 1);
  413.  
  414.     UINT* pItems = new UINT[pData->wItemCount];
  415.     for (int i = 0; i < pData->wItemCount; i++)
  416.         pItems[i] = pData->items()[i];
  417.     BOOL bResult = SetButtons(pItems, pData->wItemCount);
  418.     delete[] pItems;
  419.  
  420.     if (bResult)
  421.     {
  422.         // set new sizes of the buttons
  423.         CSize sizeImage(pData->wWidth, pData->wHeight);
  424.         CSize sizeButton(pData->wWidth + 7, pData->wHeight + 7);
  425.         SetSizes(sizeButton, sizeImage);
  426.  
  427.         // load bitmap now that sizes are known by the toolbar control
  428.         bResult = LoadBitmap(lpszResourceName);
  429.     }
  430.  
  431.     UnlockResource(hGlobal);
  432.     FreeResource(hGlobal);
  433.  
  434.     return bResult;
  435. }
  436.  
  437. BOOL CToolBar::LoadBitmap(LPCTSTR lpszResourceName)
  438. {
  439.     ASSERT_VALID(this);
  440.     ASSERT(lpszResourceName != NULL);
  441.  
  442.     // determine location of the bitmap in resource fork
  443.     HINSTANCE hInstImageWell = AfxFindResourceHandle(lpszResourceName, RT_BITMAP);
  444.     HRSRC hRsrcImageWell = ::FindResource(hInstImageWell, lpszResourceName, RT_BITMAP);
  445.     if (hRsrcImageWell == NULL)
  446.         return FALSE;
  447.  
  448. #if defined(_WIN32_WCE)
  449.     HBITMAP hbmImageWell;
  450.     hbmImageWell = ::LoadBitmap(hInstImageWell, lpszResourceName);
  451.     HIMAGELIST hImageList = (HIMAGELIST)DefWindowProc(TB_GETIMAGELIST, 0, 0);
  452.     if((m_pWndCommandBar != NULL) && (hImageList != NULL) && 
  453.         m_pWndCommandBar->m_bAppendBitmaps)
  454.     {
  455.         // Wince: Don't replace existing bitmaps because they might be adornments,
  456.         // so append to the ImageList directly.  
  457.         if(ImageList_Add(hImageList, hbmImageWell, NULL) < 0)
  458.             return FALSE;
  459.     }
  460.     else
  461.     {
  462.         if (!AddReplaceBitmap(hbmImageWell))
  463.             return FALSE;
  464.         if(m_pWndCommandBar != NULL)
  465.             m_pWndCommandBar->m_bAppendBitmaps = TRUE;
  466.     }
  467. #else // _WIN32_WCE
  468.     // load the bitmap
  469.     HBITMAP hbmImageWell;
  470.     hbmImageWell = AfxLoadSysColorBitmap(hInstImageWell, hRsrcImageWell);
  471.  
  472.     // tell common control toolbar about the new bitmap
  473.     if (!AddReplaceBitmap(hbmImageWell))
  474.         return FALSE;
  475. #endif // _WIN32_WCE
  476.  
  477.  
  478.     // remember the resource handles so the bitmap can be recolored if necessary
  479.     m_hInstImageWell = hInstImageWell;
  480.     m_hRsrcImageWell = hRsrcImageWell;
  481.     return TRUE;
  482. }
  483.  
  484. BOOL CToolBar::SetBitmap(HBITMAP hbmImageWell)
  485. {
  486.     ASSERT_VALID(this);
  487.     ASSERT(hbmImageWell != NULL);
  488.  
  489.     // the caller must manage changing system colors
  490.     m_hInstImageWell = NULL;
  491.     m_hRsrcImageWell = NULL;
  492.  
  493.     // tell common control toolbar about the new bitmap
  494.     return AddReplaceBitmap(hbmImageWell);
  495. }
  496.  
  497. BOOL CToolBar::AddReplaceBitmap(HBITMAP hbmImageWell)
  498. {
  499.     // need complete bitmap size to determine number of images
  500.     BITMAP bitmap;
  501.     VERIFY(::GetObject(hbmImageWell, sizeof(BITMAP), &bitmap));
  502.  
  503.     // add the bitmap to the common control toolbar
  504.     BOOL bResult;
  505.  
  506.     if (m_hbmImageWell == NULL)
  507.     {
  508.         TBADDBITMAP addBitmap;
  509.         addBitmap.hInst = NULL; // makes TBADDBITMAP::nID behave a HBITMAP
  510.         addBitmap.nID = (UINT)hbmImageWell;
  511.         bResult =  DefWindowProc(TB_ADDBITMAP,
  512.             bitmap.bmWidth / m_sizeImage.cx, (LPARAM)&addBitmap) == 0;
  513. #if defined(_WIN32_WCE)
  514.         bResult = TRUE; // Under some cases, TB_ADDBIMAP works, but it returns FALSE
  515. #endif // _WIN32_WCE
  516.     }
  517.     else
  518.     {
  519.         TBREPLACEBITMAP replaceBitmap;
  520.         replaceBitmap.hInstOld = NULL;
  521.         replaceBitmap.nIDOld = (UINT)m_hbmImageWell;
  522.         replaceBitmap.hInstNew = NULL;
  523.         replaceBitmap.nIDNew = (UINT)hbmImageWell;
  524.         replaceBitmap.nButtons = bitmap.bmWidth / m_sizeImage.cx;
  525.         bResult = (BOOL)DefWindowProc(TB_REPLACEBITMAP, 0,
  526.             (LPARAM)&replaceBitmap);
  527.     }
  528.     // remove old bitmap, if present
  529.     if (bResult)
  530.     {
  531.         AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell);
  532.         m_hbmImageWell = hbmImageWell;
  533.     }
  534.  
  535.     return bResult;
  536. }
  537.  
  538. BOOL CToolBar::SetButtons(const UINT* lpIDArray, int nIDCount) 
  539. {
  540.     ASSERT_VALID(this);
  541.     ASSERT(nIDCount >= 1);  // must be at least one of them
  542.     ASSERT(lpIDArray == NULL ||
  543.         AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));
  544.  
  545.     // delete all existing buttons
  546.     int nCount = (int)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  547. #if defined(_WIN32_WCE)
  548.     int iImageStart=0;
  549.     if(m_pWndCommandBar != NULL)
  550.     {
  551.         // Offset bitmap indices 
  552.         HIMAGELIST hImageList = (HIMAGELIST)DefWindowProc(TB_GETIMAGELIST, 0, 0);
  553.         if(hImageList != NULL)
  554.             iImageStart = ImageList_GetImageCount(hImageList);
  555.     }
  556.     else
  557. #endif // _WIN32_WCE
  558.     while (nCount--)
  559.         VERIFY(DefWindowProc(TB_DELETEBUTTON, 0, 0));
  560.  
  561.     TBBUTTON button; memset(&button, 0, sizeof(TBBUTTON));
  562.     button.iString = -1;
  563.     if (lpIDArray != NULL)
  564.     {
  565.         // add new buttons to the common control
  566.         int iImage = WCE_IF(iImageStart, 0);
  567.         for (int i = 0; i < nIDCount; i++)
  568.         {
  569.             button.fsState = TBSTATE_ENABLED;
  570.             if ((button.idCommand = *lpIDArray++) == 0)
  571.             {
  572.                 // separator
  573.                 button.fsStyle = TBSTYLE_SEP;
  574.                 // width of separator includes 8 pixel overlap
  575. #if defined(_WIN32_WCE)
  576.                 button.iBitmap = 6;
  577. #else // _WIN32_WCE
  578.                 ASSERT(_afxComCtlVersion != -1);
  579.                 if ((GetStyle() & TBSTYLE_FLAT) || _afxComCtlVersion == VERSION_IE4)
  580.                     button.iBitmap = 6;
  581.                 else
  582.                     button.iBitmap = 8;
  583. #endif // _WIN32_WCE
  584.             }
  585.             else
  586.             {
  587. #if defined(_WIN32_WCE)
  588. // WinCE: Don't command ID's that are reserved for adornments
  589.                 if(m_pWndCommandBar != NULL)
  590.                 {
  591.                     VERIFY((button.idCommand != IDOK) && 
  592.                            (button.idCommand != WM_HELP) && 
  593.                            (button.idCommand != WM_CLOSE));
  594.                 }
  595. #endif // _WIN32_WCE
  596.                 // a command button with image
  597.                 button.fsStyle = TBSTYLE_BUTTON;
  598.                 button.iBitmap = iImage++;
  599.             }
  600.             if (!DefWindowProc(TB_ADDBUTTONS, 1, (LPARAM)&button))
  601.                 return FALSE; 
  602.         }
  603.     }
  604.     else
  605.     {
  606.         // add 'blank' buttons
  607.         button.fsState = TBSTATE_ENABLED;
  608.         for (int i = 0; i < nIDCount; i++)
  609.         {
  610.             ASSERT(button.fsStyle == TBSTYLE_BUTTON);
  611.             if (!DefWindowProc(TB_ADDBUTTONS, 1, (LPARAM)&button))
  612.                 return FALSE;
  613.         }
  614.     }
  615.     m_nCount = (int)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  616.     m_bDelayedButtonLayout = TRUE;
  617.  
  618.     return TRUE;
  619. }
  620.  
  621. #ifdef AFX_CORE3_SEG
  622. #pragma code_seg(AFX_CORE3_SEG)
  623. #endif
  624.  
  625. /////////////////////////////////////////////////////////////////////////////
  626. // CToolBar attribute access
  627.  
  628. void CToolBar::_GetButton(int nIndex, TBBUTTON* pButton) const
  629. {
  630.     CToolBar* pBar = (CToolBar*)this;
  631.     VERIFY(pBar->DefWindowProc(TB_GETBUTTON, nIndex, (LPARAM)pButton));
  632.     // TBSTATE_ENABLED == TBBS_DISABLED so invert it
  633.     pButton->fsState ^= TBSTATE_ENABLED;
  634. }
  635.  
  636. void CToolBar::_SetButton(int nIndex, TBBUTTON* pButton)
  637. {
  638.     // get original button state
  639.     TBBUTTON button;
  640.     VERIFY(DefWindowProc(TB_GETBUTTON, nIndex, (LPARAM)&button));
  641.  
  642.     // prepare for old/new button comparsion
  643.     button.bReserved[0] = 0;
  644.     button.bReserved[1] = 0;
  645.     // TBSTATE_ENABLED == TBBS_DISABLED so invert it
  646.     pButton->fsState ^= TBSTATE_ENABLED;
  647.     pButton->bReserved[0] = 0;
  648.     pButton->bReserved[1] = 0;
  649.  
  650.     // nothing to do if they are the same
  651.     if (memcmp(pButton, &button, sizeof(TBBUTTON)) != 0)
  652.     {
  653.         // don't redraw everything while setting the button
  654.         DWORD dwStyle = GetStyle();
  655.         ModifyStyle(WS_VISIBLE, 0);
  656.         VERIFY(DefWindowProc(TB_DELETEBUTTON, nIndex, 0));
  657.         VERIFY(DefWindowProc(TB_INSERTBUTTON, nIndex, (LPARAM)pButton));
  658.         ModifyStyle(0, dwStyle & WS_VISIBLE);
  659.  
  660.         // invalidate appropriate parts
  661.         if (((pButton->fsStyle ^ button.fsStyle) & TBSTYLE_SEP) ||
  662.             ((pButton->fsStyle & TBSTYLE_SEP) && pButton->iBitmap != button.iBitmap))
  663.         {
  664.             // changing a separator
  665.             Invalidate();
  666.         }
  667.         else
  668.         {
  669.             // invalidate just the button
  670.             CRect rect;
  671.             if (DefWindowProc(TB_GETITEMRECT, nIndex, (LPARAM)&rect))
  672.                 InvalidateRect(rect);
  673.         }
  674.     }
  675. }
  676.  
  677. int CToolBar::CommandToIndex(UINT nIDFind) const
  678. {
  679.     ASSERT_VALID(this);
  680.     ASSERT(::IsWindow(m_hWnd));
  681.  
  682.     CToolBar* pBar = (CToolBar*)this;
  683.     return (int)pBar->DefWindowProc(TB_COMMANDTOINDEX, nIDFind, 0);
  684. }
  685.  
  686. UINT CToolBar::GetItemID(int nIndex) const
  687. {
  688.     ASSERT_VALID(this);
  689.     ASSERT(::IsWindow(m_hWnd));
  690.  
  691.     TBBUTTON button;
  692.     _GetButton(nIndex, &button);
  693.     return button.idCommand;
  694. }
  695.  
  696. void CToolBar::GetItemRect(int nIndex, LPRECT lpRect) const
  697. {
  698.     ASSERT_VALID(this);
  699.     ASSERT(::IsWindow(m_hWnd));
  700.  
  701.     // handle any delayed layout
  702.     if (m_bDelayedButtonLayout)
  703.         ((CToolBar*)this)->Layout();
  704.  
  705.     // now it is safe to get the item rectangle
  706.     CToolBar* pBar = (CToolBar*)this;
  707.     if (!pBar->DefWindowProc(TB_GETITEMRECT, nIndex, (LPARAM)lpRect))
  708.         SetRectEmpty(lpRect);
  709. }
  710.  
  711. void CToolBar::Layout()
  712. {
  713.     ASSERT(m_bDelayedButtonLayout);
  714.  
  715.     m_bDelayedButtonLayout = FALSE;
  716.  
  717.     BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) != 0;
  718.     if ((m_dwStyle & CBRS_FLOATING) && (m_dwStyle & CBRS_SIZE_DYNAMIC))
  719.         ((CToolBar*)this)->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH | LM_COMMIT);
  720.     else if (bHorz)
  721.         ((CToolBar*)this)->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK | LM_COMMIT);
  722.     else
  723.         ((CToolBar*)this)->CalcDynamicLayout(0, LM_VERTDOCK | LM_COMMIT);
  724. }
  725.  
  726. UINT CToolBar::GetButtonStyle(int nIndex) const
  727. {
  728.     ASSERT_VALID(this);
  729.     ASSERT(::IsWindow(m_hWnd));
  730.  
  731.     TBBUTTON button;
  732.     _GetButton(nIndex, &button);
  733.     return MAKELONG(button.fsStyle, button.fsState);
  734. }
  735.  
  736. void CToolBar::SetButtonStyle(int nIndex, UINT nStyle)
  737. {
  738.     ASSERT_VALID(this);
  739.     ASSERT(::IsWindow(m_hWnd));
  740.  
  741.     TBBUTTON button;
  742.     _GetButton(nIndex, &button);
  743.     if (button.fsStyle != (BYTE)LOWORD(nStyle) || button.fsState != (BYTE)HIWORD(nStyle))
  744.     {
  745.         button.fsStyle = (BYTE)LOWORD(nStyle);
  746.         button.fsState = (BYTE)HIWORD(nStyle);
  747.         _SetButton(nIndex, &button);
  748.         m_bDelayedButtonLayout = TRUE;
  749.     }
  750. }
  751.  
  752. #define CX_OVERLAP  0
  753.  
  754. CSize CToolBar::CalcSize(TBBUTTON* pData, int nCount)
  755. {
  756.     ASSERT(pData != NULL && nCount > 0);
  757.  
  758.     CPoint cur(0,0);
  759.     CSize sizeResult(0,0);
  760.  
  761. #if !defined(_WIN32_WCE)
  762.     DWORD dwExtendedStyle = DefWindowProc(TB_GETEXTENDEDSTYLE, 0, 0);
  763. #endif // _WIN32_WCE
  764.  
  765.     for (int i = 0; i < nCount; i++)
  766.     {
  767.         //WINBUG: The IE4 version of COMCTL32.DLL calculates the separation
  768.         //    on a TBSTYLE_WRAP button as 100% of the value in iBitmap compared
  769.         //    to the other versions which calculate it at 2/3 of that value.
  770.         //    This is actually a bug which should be fixed in IE 4.01, so we
  771.         //    only do the 100% calculation specifically for IE4.
  772.         int cySep = pData[i].iBitmap;
  773. #if !defined(_WIN32_WCE)
  774.         ASSERT(_afxComCtlVersion != -1);
  775.         if (!(GetStyle() & TBSTYLE_FLAT) && _afxComCtlVersion != VERSION_IE4)
  776.             cySep = cySep * 2 / 3;
  777. #endif // _WIN32_WCE
  778.  
  779.         if (pData[i].fsState & TBSTATE_HIDDEN)
  780.             continue;
  781.  
  782.         int cx = m_sizeButton.cx;
  783.         if (pData[i].fsStyle & TBSTYLE_SEP)
  784.         {
  785.             // a separator represents either a height or width
  786.             if (pData[i].fsState & TBSTATE_WRAP)
  787.                 sizeResult.cy = max(cur.y + m_sizeButton.cy + cySep, sizeResult.cy);
  788.             else
  789.                 sizeResult.cx = max(cur.x + pData[i].iBitmap, sizeResult.cx);
  790. #if defined(_WIN32_WCE)
  791. // WinCE: Get the height of custom controls 
  792.             if(CCeCommandBar::IsCustomControlButton(pData[i]))
  793.                 sizeResult.cy = max(cur.y + m_sizeButton.cy, sizeResult.cy);
  794. #endif 
  795.         }
  796.         else 
  797.         {
  798. #if !defined(_WIN32_WCE)
  799.             // check for dropdown style, but only if the buttons are being drawn
  800.             if ((pData[i].fsStyle & TBSTYLE_DROPDOWN) && 
  801.                 (dwExtendedStyle & TBSTYLE_EX_DRAWDDARROWS))
  802.             {
  803.                 // add size of drop down
  804.                 ASSERT(_afxDropDownWidth != -1);
  805.                 cx += _afxDropDownWidth;
  806.             }
  807. #endif // _WIN32_WCE
  808.             sizeResult.cx = max(cur.x + cx, sizeResult.cx);
  809.             sizeResult.cy = max(cur.y + m_sizeButton.cy, sizeResult.cy);
  810.         }
  811.  
  812.         if (pData[i].fsStyle & TBSTYLE_SEP)
  813.             cur.x += pData[i].iBitmap;
  814.         else
  815.             cur.x += cx - CX_OVERLAP;
  816.  
  817.         if (pData[i].fsState & TBSTATE_WRAP)
  818.         {
  819.             cur.x = 0;
  820.             cur.y += m_sizeButton.cy;
  821.             if (pData[i].fsStyle & TBSTYLE_SEP)
  822.                 cur.y += cySep;
  823.         }
  824.     }
  825.     return sizeResult;
  826. }
  827.  
  828. int CToolBar::WrapToolBar(TBBUTTON* pData, int nCount, int nWidth)
  829. {
  830.     ASSERT(pData != NULL && nCount > 0);
  831.  
  832.     int nResult = 0;
  833.     int x = 0;
  834.     for (int i = 0; i < nCount; i++)
  835.     {
  836.         pData[i].fsState &= ~TBSTATE_WRAP;
  837.  
  838.         if (pData[i].fsState & TBSTATE_HIDDEN)
  839.             continue;
  840.  
  841.         int dx, dxNext;
  842.         if (pData[i].fsStyle & TBSTYLE_SEP)
  843.         {
  844.             dx = pData[i].iBitmap;
  845.             dxNext = dx;
  846.         }
  847.         else
  848.         {
  849.             dx = m_sizeButton.cx;
  850.             dxNext = dx - CX_OVERLAP;
  851.         }
  852.  
  853.         if (x + dx > nWidth)
  854.         {
  855.             BOOL bFound = FALSE;
  856.             for (int j = i; j >= 0  &&  !(pData[j].fsState & TBSTATE_WRAP); j--)
  857.             {
  858.                 // Find last separator that isn't hidden
  859.                 // a separator that has a command ID is not
  860.                 // a separator, but a custom control.
  861.                 if ((pData[j].fsStyle & TBSTYLE_SEP) &&
  862.                     (pData[j].idCommand == 0) &&
  863.                     !(pData[j].fsState & TBSTATE_HIDDEN))
  864.                 {
  865.                     bFound = TRUE; i = j; x = 0;
  866.                     pData[j].fsState |= TBSTATE_WRAP;
  867.                     nResult++;
  868.                     break;
  869.                 }
  870.             }
  871.             if (!bFound)
  872.             {
  873.                 for (int j = i - 1; j >= 0 && !(pData[j].fsState & TBSTATE_WRAP); j--)
  874.                 {
  875.                     // Never wrap anything that is hidden,
  876.                     // or any custom controls
  877.                     if ((pData[j].fsState & TBSTATE_HIDDEN) ||
  878.                         ((pData[j].fsStyle & TBSTYLE_SEP) &&
  879.                         (pData[j].idCommand != 0)))
  880.                         continue;
  881.  
  882.                     bFound = TRUE; i = j; x = 0;
  883.                     pData[j].fsState |= TBSTATE_WRAP;
  884.                     nResult++;
  885.                     break;
  886.                 }
  887.                 if (!bFound)
  888.                     x += dxNext;
  889.             }
  890.         }
  891.         else
  892.             x += dxNext;
  893.     }
  894.     return nResult + 1;
  895. }
  896.  
  897. void  CToolBar::SizeToolBar(TBBUTTON* pData, int nCount, int nLength, BOOL bVert)
  898. {
  899.     ASSERT(pData != NULL && nCount > 0);
  900.  
  901.     if (!bVert)
  902.     {
  903.         int nMin, nMax, nTarget, nCurrent, nMid;
  904.  
  905.         // Wrap ToolBar as specified
  906.         nMax = nLength;
  907.         nTarget = WrapToolBar(pData, nCount, nMax);
  908.  
  909.         // Wrap ToolBar vertically
  910.         nMin = 0;
  911.         nCurrent = WrapToolBar(pData, nCount, nMin);
  912.  
  913.         if (nCurrent != nTarget)
  914.         {
  915.             while (nMin < nMax)
  916.             {
  917.                 nMid = (nMin + nMax) / 2;
  918.                 nCurrent = WrapToolBar(pData, nCount, nMid);
  919.  
  920.                 if (nCurrent == nTarget)
  921.                     nMax = nMid;
  922.                 else
  923.                 {
  924.                     if (nMin == nMid)
  925.                     {
  926.                         WrapToolBar(pData, nCount, nMax);
  927.                         break;
  928.                     }
  929.                     nMin = nMid;
  930.                 }
  931.             }
  932.         }
  933.         CSize size = CalcSize(pData, nCount);
  934.         WrapToolBar(pData, nCount, size.cx);
  935.     }
  936.     else
  937.     {
  938.         CSize sizeMax, sizeMin, sizeMid;
  939.  
  940.         // Wrap ToolBar vertically
  941.         WrapToolBar(pData, nCount, 0);
  942.         sizeMin = CalcSize(pData, nCount);
  943.  
  944.         // Wrap ToolBar horizontally
  945.         WrapToolBar(pData, nCount, 32767);
  946.         sizeMax = CalcSize(pData, nCount);
  947.  
  948.         while (sizeMin.cx < sizeMax.cx)
  949.         {
  950.             sizeMid.cx = (sizeMin.cx + sizeMax.cx) / 2;
  951.             WrapToolBar(pData, nCount, sizeMid.cx);
  952.             sizeMid = CalcSize(pData, nCount);
  953.  
  954.             if (nLength < sizeMid.cy)
  955.             {
  956.                 if (sizeMin == sizeMid)
  957.                 {
  958.                     WrapToolBar(pData, nCount, sizeMax.cx);
  959.                     return;
  960.                 }
  961.                 sizeMin = sizeMid;
  962.             }
  963.             else if (nLength > sizeMid.cy)
  964.                 sizeMax = sizeMid;
  965.             else
  966.                 return;
  967.         }
  968.     }
  969. }
  970.  
  971. struct _AFX_CONTROLPOS
  972. {
  973.     int nIndex, nID;
  974.     CRect rectOldPos;
  975. };
  976.  
  977. CSize CToolBar::CalcLayout(DWORD dwMode, int nLength)
  978. {
  979.     ASSERT_VALID(this);
  980.     ASSERT(::IsWindow(m_hWnd));
  981.     if (dwMode & LM_HORZDOCK)
  982.         ASSERT(dwMode & LM_HORZ);
  983.  
  984.     int nCount;
  985.     TBBUTTON* pData = NULL;
  986.     CSize sizeResult(0,0);
  987.  
  988.     //BLOCK: Load Buttons
  989.     {
  990.         nCount = DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  991.         if (nCount != 0)
  992.         {
  993.             int i;
  994.             pData = new TBBUTTON[nCount];
  995.             for (i = 0; i < nCount; i++)
  996.                 _GetButton(i, &pData[i]);
  997.         }
  998.     }
  999.  
  1000.     if (nCount > 0)
  1001.     {
  1002.         if (!(m_dwStyle & CBRS_SIZE_FIXED))
  1003.         {
  1004.             BOOL bDynamic = m_dwStyle & CBRS_SIZE_DYNAMIC;
  1005.  
  1006.             if (bDynamic && (dwMode & LM_MRUWIDTH))
  1007.                 SizeToolBar(pData, nCount, m_nMRUWidth);
  1008.             else if (bDynamic && (dwMode & LM_HORZDOCK))
  1009.                 SizeToolBar(pData, nCount, 32767);
  1010.             else if (bDynamic && (dwMode & LM_VERTDOCK))
  1011.                 SizeToolBar(pData, nCount, 0);
  1012.             else if (bDynamic && (nLength != -1))
  1013.             {
  1014.                 CRect rect; rect.SetRectEmpty();
  1015.                 CalcInsideRect(rect, (dwMode & LM_HORZ));
  1016.                 BOOL bVert = (dwMode & LM_LENGTHY);
  1017.                 int nLen = nLength + (bVert ? rect.Height() : rect.Width());
  1018.  
  1019.                 SizeToolBar(pData, nCount, nLen, bVert);
  1020.             }
  1021.             else if (bDynamic && (m_dwStyle & CBRS_FLOATING))
  1022.                 SizeToolBar(pData, nCount, m_nMRUWidth);
  1023.             else
  1024.                 SizeToolBar(pData, nCount, (dwMode & LM_HORZ) ? 32767 : 0);
  1025.         }
  1026.  
  1027.         sizeResult = CalcSize(pData, nCount);
  1028.  
  1029.         if (dwMode & LM_COMMIT)
  1030.         {
  1031.             _AFX_CONTROLPOS* pControl = NULL;
  1032.             int nControlCount = 0;
  1033.             BOOL bIsDelayed = m_bDelayedButtonLayout;
  1034.             m_bDelayedButtonLayout = FALSE;
  1035.  
  1036.             for (int i = 0; i < nCount; i++)
  1037.                 if ((pData[i].fsStyle & TBSTYLE_SEP) && (pData[i].idCommand != 0))
  1038.                     nControlCount++;
  1039.  
  1040.             if (nControlCount > 0)
  1041.             {
  1042.                 pControl = new _AFX_CONTROLPOS[nControlCount];
  1043.                 nControlCount = 0;
  1044.  
  1045.                 for(int i = 0; i < nCount; i++)
  1046.                 {
  1047.                     if ((pData[i].fsStyle & TBSTYLE_SEP) && (pData[i].idCommand != 0))
  1048.                     {
  1049.                         pControl[nControlCount].nIndex = i;
  1050.                         pControl[nControlCount].nID = pData[i].idCommand;
  1051.  
  1052.                         CRect rect;
  1053.                         GetItemRect(i, &rect);
  1054.                         ClientToScreen(&rect);
  1055.                         pControl[nControlCount].rectOldPos = rect;
  1056.  
  1057.                         nControlCount++;
  1058.                     }
  1059.                 }
  1060.             }
  1061.  
  1062.             if ((m_dwStyle & CBRS_FLOATING) && (m_dwStyle & CBRS_SIZE_DYNAMIC))
  1063.                 m_nMRUWidth = sizeResult.cx;
  1064.             for (i = 0; i < nCount; i++)
  1065.                 _SetButton(i, &pData[i]);
  1066.  
  1067.             if (nControlCount > 0)
  1068.             {
  1069.                 for (int i = 0; i < nControlCount; i++)
  1070.                 {
  1071.                     CWnd* pWnd = GetDlgItem(pControl[i].nID);
  1072.                     if (pWnd != NULL)
  1073.                     {
  1074.                         CRect rect;
  1075.                         pWnd->GetWindowRect(&rect);
  1076.                         CPoint pt = rect.TopLeft() - pControl[i].rectOldPos.TopLeft();
  1077.                         GetItemRect(pControl[i].nIndex, &rect);
  1078.                         pt = rect.TopLeft() + pt;
  1079.                         pWnd->SetWindowPos(NULL, pt.x, pt.y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  1080.                     }
  1081.                 }
  1082.                 delete[] pControl;
  1083.             }
  1084.             m_bDelayedButtonLayout = bIsDelayed;
  1085.         }
  1086.         delete[] pData;
  1087.     }
  1088.  
  1089.     //BLOCK: Adjust Margins
  1090.     {
  1091.         CRect rect; rect.SetRectEmpty();
  1092.         CalcInsideRect(rect, (dwMode & LM_HORZ));
  1093.         sizeResult.cy -= rect.Height();
  1094.         sizeResult.cx -= rect.Width();
  1095.  
  1096.         CSize size = CControlBar::CalcFixedLayout((dwMode & LM_STRETCH), (dwMode & LM_HORZ));
  1097.         sizeResult.cx = max(sizeResult.cx, size.cx);
  1098.         sizeResult.cy = max(sizeResult.cy, size.cy);
  1099.     }
  1100.     return sizeResult;
  1101. }
  1102.  
  1103. CSize CToolBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  1104. {
  1105.     DWORD dwMode = bStretch ? LM_STRETCH : 0;
  1106.     dwMode |= bHorz ? LM_HORZ : 0;
  1107.  
  1108.     return CalcLayout(dwMode);
  1109. }
  1110.  
  1111. CSize CToolBar::CalcDynamicLayout(int nLength, DWORD dwMode)
  1112. {
  1113.     if ((nLength == -1) && !(dwMode & LM_MRUWIDTH) && !(dwMode & LM_COMMIT) &&
  1114.         ((dwMode & LM_HORZDOCK) || (dwMode & LM_VERTDOCK)))
  1115.     {
  1116.         return CalcFixedLayout(dwMode & LM_STRETCH, dwMode & LM_HORZDOCK);
  1117.     }
  1118.     return CalcLayout(dwMode, nLength);
  1119. }
  1120.  
  1121. void CToolBar::GetButtonInfo(int nIndex, UINT& nID, UINT& nStyle, int& iImage) const
  1122. {
  1123.     ASSERT_VALID(this);
  1124.     ASSERT(::IsWindow(m_hWnd));
  1125.  
  1126.     TBBUTTON button;
  1127.     _GetButton(nIndex, &button);
  1128.     nID = button.idCommand;
  1129.     nStyle = MAKELONG(button.fsStyle, button.fsState);
  1130.     iImage = button.iBitmap;
  1131. }
  1132.  
  1133. void CToolBar::SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage)
  1134. {
  1135.     ASSERT_VALID(this);
  1136.  
  1137.     TBBUTTON button;
  1138.     _GetButton(nIndex, &button);
  1139.     TBBUTTON save;
  1140.     memcpy(&save, &button, sizeof(save));
  1141.     button.idCommand = nID;
  1142.     button.iBitmap = iImage;
  1143.     button.fsStyle = (BYTE)LOWORD(nStyle);
  1144.     button.fsState = (BYTE)HIWORD(nStyle);
  1145.     if (memcmp(&save, &button, sizeof(save)) != 0)
  1146.     {
  1147.         _SetButton(nIndex, &button);
  1148.         m_bDelayedButtonLayout = TRUE;
  1149.     }
  1150. }
  1151.  
  1152. #if !defined(_WIN32_WCE_NO_TOOLTIPS)
  1153. int CToolBar::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
  1154. {
  1155.     ASSERT_VALID(this);
  1156.     ASSERT(::IsWindow(m_hWnd));
  1157.  
  1158.     // check child windows first by calling CControlBar
  1159.     int nHit = CControlBar::OnToolHitTest(point, pTI);
  1160.     if (nHit != -1)
  1161.         return nHit;
  1162.  
  1163.     // now hit test against CToolBar buttons
  1164.     CToolBar* pBar = (CToolBar*)this;
  1165.     int nButtons = (int)pBar->DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  1166.     for (int i = 0; i < nButtons; i++)
  1167.     {
  1168.         CRect rect;
  1169.         TBBUTTON button;
  1170.         if (pBar->DefWindowProc(TB_GETITEMRECT, i, (LPARAM)&rect))
  1171.         {
  1172.             ++rect.bottom;
  1173.             ++rect.right;
  1174.             if (rect.PtInRect(point) &&
  1175.                 pBar->DefWindowProc(TB_GETBUTTON, i, (LPARAM)&button) &&
  1176.                 !(button.fsStyle & TBSTYLE_SEP))
  1177.             {
  1178.                 int nHit = GetItemID(i);
  1179.                 if (pTI != NULL && pTI->cbSize >= sizeof(AFX_OLDTOOLINFO))
  1180.                 {
  1181.                     pTI->hwnd = m_hWnd;
  1182.                     pTI->rect = rect;
  1183.                     pTI->uId = nHit;
  1184.                     pTI->lpszText = LPSTR_TEXTCALLBACK;
  1185.                 }
  1186.                 // found matching rect, return the ID of the button
  1187.                 return nHit != 0 ? nHit : -1;
  1188.             }
  1189.         }
  1190.     }
  1191.     return -1;
  1192. }
  1193. #endif // _WIN32_WCE_NO_TOOLTIPS
  1194.  
  1195. BOOL CToolBar::SetButtonText(int nIndex, LPCTSTR lpszText)
  1196. {
  1197.     // attempt to lookup string index in map
  1198.     int nString = -1;
  1199.     void* p;
  1200.     if (m_pStringMap != NULL && m_pStringMap->Lookup(lpszText, p))
  1201.         nString = (int)p;
  1202.  
  1203.     // add new string if not already in map
  1204.     if (nString == -1)
  1205.     {
  1206.         // initialize map if necessary
  1207.         if (m_pStringMap == NULL)
  1208.             m_pStringMap = new CMapStringToPtr;
  1209.  
  1210.         // add new string to toolbar list
  1211.         CString strTemp(lpszText, lstrlen(lpszText)+1);
  1212.         nString = (int)DefWindowProc(TB_ADDSTRING, 0, (LPARAM)(LPCTSTR)strTemp);
  1213.         if (nString == -1)
  1214.             return FALSE;
  1215.  
  1216.         // cache string away in string map
  1217.         m_pStringMap->SetAt(lpszText, (void*)nString);
  1218.         ASSERT(m_pStringMap->Lookup(lpszText, p));
  1219.     }
  1220.  
  1221.     // change the toolbar button description
  1222.     TBBUTTON button;
  1223.     _GetButton(nIndex, &button);
  1224.     button.iString = nString;
  1225.     _SetButton(nIndex, &button);
  1226.  
  1227.     return TRUE;
  1228. }
  1229.  
  1230. CString CToolBar::GetButtonText(int nIndex) const
  1231. {
  1232.     CString strResult;
  1233.     GetButtonText(nIndex, strResult);
  1234.     return strResult;
  1235. }
  1236.  
  1237. void CToolBar::GetButtonText(int nIndex, CString& rString) const
  1238. {
  1239.     if (m_pStringMap != NULL)
  1240.     {
  1241.         // get button information (need button.iString)
  1242.         TBBUTTON button;
  1243.         _GetButton(nIndex, &button);
  1244.  
  1245.         // look in map for matching iString
  1246.         POSITION pos = m_pStringMap->GetStartPosition();
  1247.         CString str; void* p;
  1248.         while (pos)
  1249.         {
  1250.             m_pStringMap->GetNextAssoc(pos, str, p);
  1251.             if ((int)p == button.iString)
  1252.             {
  1253.                 rString = str;
  1254.                 return;
  1255.             }
  1256.         }
  1257.     }
  1258.     rString.Empty();
  1259. }
  1260.  
  1261. /////////////////////////////////////////////////////////////////////////////
  1262. // CToolBar message handlers
  1263.  
  1264. BEGIN_MESSAGE_MAP(CToolBar, CControlBar)
  1265.     //{{AFX_MSG_MAP(CToolBar)
  1266. WCE_DEL    ON_WM_NCHITTEST()
  1267. WCE_DEL    ON_WM_NCPAINT()
  1268.     ON_WM_PAINT()
  1269.     ON_WM_ERASEBKGND()
  1270. WCE_DEL    ON_WM_NCCALCSIZE()
  1271. WCE_DEL    ON_WM_WINDOWPOSCHANGING()
  1272. WCE_DEL    ON_WM_NCCREATE()
  1273. WCE_DEL    ON_MESSAGE(TB_SETBITMAPSIZE, OnSetBitmapSize)
  1274. WCE_DEL    ON_MESSAGE(TB_SETBUTTONSIZE, OnSetButtonSize)
  1275. WCE_DEL    ON_MESSAGE(WM_SETTINGCHANGE, OnPreserveZeroBorderHelper)
  1276. WCE_DEL    ON_MESSAGE(WM_SETFONT, OnPreserveZeroBorderHelper)
  1277. WCE_DEL ON_WM_SYSCOLORCHANGE()
  1278.     //}}AFX_MSG_MAP
  1279. END_MESSAGE_MAP()
  1280.  
  1281. BOOL CToolBar::OnEraseBkgnd(CDC*)
  1282. {
  1283.     return (BOOL)Default();
  1284. }
  1285.  
  1286. #if !defined(_WIN32_WCE)
  1287. UINT CToolBar::OnNcHitTest(CPoint)
  1288. {
  1289.     return HTCLIENT;
  1290. }
  1291.  
  1292. void CToolBar::OnNcCalcSize(BOOL /*bCalcValidRects*/, NCCALCSIZE_PARAMS* lpncsp)
  1293. {
  1294.     // calculate border space (will add to top/bottom, subtract from right/bottom)
  1295.     CRect rect; rect.SetRectEmpty();
  1296.     BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) != 0;
  1297.     CControlBar::CalcInsideRect(rect, bHorz);
  1298.     ASSERT(_afxComCtlVersion != -1);
  1299.     ASSERT(_afxComCtlVersion >= VERSION_IE4 || rect.top >= 2);
  1300.  
  1301.     // adjust non-client area for border space
  1302.     lpncsp->rgrc[0].left += rect.left;
  1303.     lpncsp->rgrc[0].top += rect.top;
  1304.     // previous versions of COMCTL32.DLL had a built-in 2 pixel border
  1305.     if (_afxComCtlVersion < VERSION_IE4)
  1306.         lpncsp->rgrc[0].top -= 2;
  1307.     lpncsp->rgrc[0].right += rect.right;
  1308.     lpncsp->rgrc[0].bottom += rect.bottom;
  1309. }
  1310. #endif // _WIN32_WCE
  1311.  
  1312. void CToolBar::OnBarStyleChange(DWORD dwOldStyle, DWORD dwNewStyle)
  1313. {
  1314.     // a dynamically resizeable toolbar can not have the CBRS_FLOAT_MULTI
  1315.     ASSERT(!((dwNewStyle & CBRS_SIZE_DYNAMIC) &&
  1316.             (m_dwDockStyle & CBRS_FLOAT_MULTI)));
  1317.  
  1318.     // a toolbar can not be both dynamic and fixed in size
  1319.     ASSERT (!((dwNewStyle & CBRS_SIZE_FIXED) &&
  1320.         (dwNewStyle & CBRS_SIZE_DYNAMIC)));
  1321.  
  1322.     // CBRS_SIZE_DYNAMIC can not be disabled once it has been enabled
  1323.     ASSERT (((dwOldStyle & CBRS_SIZE_DYNAMIC) == 0) ||
  1324.         ((dwNewStyle & CBRS_SIZE_DYNAMIC) != 0));
  1325.  
  1326.     if (m_hWnd != NULL &&
  1327.         ((dwOldStyle & CBRS_BORDER_ANY) != (dwNewStyle & CBRS_BORDER_ANY)))
  1328.     {
  1329.         // recalc non-client area when border styles change
  1330.         SetWindowPos(NULL, 0, 0, 0, 0,
  1331.             SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME);
  1332.     }
  1333.     m_bDelayedButtonLayout = TRUE;
  1334. }
  1335.  
  1336. #if !defined(_WIN32_WCE)
  1337. void CToolBar::OnNcPaint()
  1338. {
  1339.     EraseNonClient();
  1340. }
  1341.  
  1342. void CToolBar::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
  1343. {
  1344.     // not necessary to invalidate the borders
  1345.     DWORD dwStyle = m_dwStyle;
  1346.     m_dwStyle &= ~(CBRS_BORDER_ANY);
  1347.     CControlBar::OnWindowPosChanging(lpWndPos);
  1348.     m_dwStyle = dwStyle;
  1349.  
  1350.     // If we can resize while floating
  1351.     if (dwStyle & CBRS_SIZE_DYNAMIC)
  1352.     {
  1353.         // And we are resizing
  1354.         if (lpWndPos->flags & SWP_NOSIZE)
  1355.             return;
  1356.  
  1357.         // Then redraw the buttons
  1358.         Invalidate();
  1359.     }
  1360. }
  1361. #endif // _WIN32_WCE
  1362.  
  1363. void CToolBar::OnPaint()
  1364. {
  1365.     if (m_bDelayedButtonLayout)
  1366.         Layout();
  1367.  
  1368.     Default();
  1369. }
  1370.  
  1371. #if !defined(_WIN32_WCE)
  1372. LRESULT CToolBar::OnSetButtonSize(WPARAM, LPARAM lParam)
  1373. {
  1374.     return OnSetSizeHelper(m_sizeButton, lParam);
  1375. }
  1376.  
  1377. LRESULT CToolBar::OnSetBitmapSize(WPARAM, LPARAM lParam)
  1378. {
  1379.     return OnSetSizeHelper(m_sizeImage, lParam);
  1380. }
  1381.  
  1382. LRESULT CToolBar::OnSetSizeHelper(CSize& size, LPARAM lParam)
  1383. {
  1384.     //WINBUG: The IE4 version of COMCTL32.DLL supports a zero border, but 
  1385.     //    only if TBSTYLE_TRANSPARENT is on during the the TB_SETBITMAPSIZE
  1386.     //    and/or TB_SETBUTTONSIZE messages.  In order to enable this feature
  1387.     //    all the time (so we get consistent border behavior, dependent only
  1388.     //    on the version of COMCTL32.DLL) we turn on TBSTYLE_TRANSPARENT 
  1389.     //    whenever these messages go through.  It would be nice that in a
  1390.     //    future version, the system toolbar would just allow you to set
  1391.     //    the top and left borders to anything you please.
  1392.  
  1393.     BOOL bModify = FALSE;
  1394.     ASSERT(_afxComCtlVersion != -1);
  1395.     DWORD dwStyle = 0;
  1396.     if (_afxComCtlVersion >= VERSION_IE4)
  1397.     {
  1398.         dwStyle = GetStyle();
  1399.         bModify = ModifyStyle(0, TBSTYLE_TRANSPARENT|TBSTYLE_FLAT);
  1400.     }
  1401.  
  1402.     LRESULT lResult = Default();
  1403.     if (lResult)
  1404.         size = lParam;
  1405.  
  1406.     if (bModify)
  1407.         SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);
  1408.  
  1409.     return lResult;
  1410. }
  1411.  
  1412. LRESULT CToolBar::OnPreserveZeroBorderHelper(WPARAM, LPARAM)
  1413. {
  1414.     BOOL bModify = FALSE;
  1415.     ASSERT(_afxComCtlVersion != -1);
  1416.     DWORD dwStyle = 0;
  1417.     if (_afxComCtlVersion >= VERSION_IE4)
  1418.     {
  1419.         dwStyle = GetStyle();
  1420.         bModify = ModifyStyle(0, TBSTYLE_TRANSPARENT|TBSTYLE_FLAT);
  1421.     }
  1422.  
  1423.     LRESULT lResult = Default();
  1424.  
  1425.     if (bModify)
  1426.         SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);
  1427.  
  1428.     return lResult;
  1429. }
  1430.  
  1431. void CToolBar::OnSysColorChange()
  1432. {
  1433.     // re-color bitmap for toolbar
  1434.     if (m_hInstImageWell != NULL && m_hbmImageWell != NULL)
  1435.     {
  1436.         HBITMAP hbmNew;
  1437.         hbmNew = AfxLoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell);
  1438.         if (hbmNew != NULL)
  1439.             AddReplaceBitmap(hbmNew);
  1440.     }
  1441. }
  1442. #endif // _WIN32_WCE
  1443.  
  1444. /////////////////////////////////////////////////////////////////////////////
  1445. // CToolBar idle update through CToolCmdUI class
  1446.  
  1447. class CToolCmdUI : public CCmdUI        // class private to this file !
  1448. {
  1449. public: // re-implementations only
  1450.     virtual void Enable(BOOL bOn);
  1451.     virtual void SetCheck(int nCheck);
  1452.     virtual void SetText(LPCTSTR lpszText);
  1453. };
  1454.  
  1455. void CToolCmdUI::Enable(BOOL bOn)
  1456. {
  1457.     m_bEnableChanged = TRUE;
  1458.     CToolBar* pToolBar = (CToolBar*)m_pOther;
  1459.     ASSERT(pToolBar != NULL);
  1460. #if defined(_WIN32_WCE)
  1461.     ASSERT(pToolBar->IsKindOf(RUNTIME_CLASS(CToolBar)) || 
  1462.            pToolBar->IsKindOf(RUNTIME_CLASS(CCeCommandBar)));
  1463. #else // _WIN32_WCE
  1464.     ASSERT_KINDOF(CToolBar, pToolBar);
  1465. #endif // _WIN32_WCE
  1466.     ASSERT(m_nIndex < m_nIndexMax);
  1467.  
  1468.     UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) & ~TBBS_DISABLED;
  1469.     if (!bOn)
  1470.     {
  1471.         nNewStyle |= TBBS_DISABLED;
  1472.         // WINBUG: If a button is currently pressed and then is disabled
  1473.         // COMCTL32.DLL does not unpress the button, even after the mouse
  1474.         // button goes up!  We work around this bug by forcing TBBS_PRESSED
  1475.         // off when a button is disabled.
  1476.         nNewStyle &= ~TBBS_PRESSED;
  1477.     }
  1478.     ASSERT(!(nNewStyle & TBBS_SEPARATOR));
  1479.     pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
  1480. }
  1481.  
  1482. void CToolCmdUI::SetCheck(int nCheck)
  1483. {
  1484.     ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
  1485.     CToolBar* pToolBar = (CToolBar*)m_pOther;
  1486.     ASSERT(pToolBar != NULL);
  1487. #if defined(_WIN32_WCE)
  1488.     ASSERT(pToolBar->IsKindOf(RUNTIME_CLASS(CToolBar)) || 
  1489.            pToolBar->IsKindOf(RUNTIME_CLASS(CCeCommandBar)));
  1490. #else // _WIN32_WCE
  1491.     ASSERT_KINDOF(CToolBar, pToolBar);
  1492. #endif // _WIN32_WCE
  1493.     ASSERT(m_nIndex < m_nIndexMax);
  1494.  
  1495.     UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) &
  1496.                 ~(TBBS_CHECKED | TBBS_INDETERMINATE);
  1497.     if (nCheck == 1)
  1498.         nNewStyle |= TBBS_CHECKED;
  1499.     else if (nCheck == 2)
  1500.         nNewStyle |= TBBS_INDETERMINATE;
  1501.     ASSERT(!(nNewStyle & TBBS_SEPARATOR));
  1502.     pToolBar->SetButtonStyle(m_nIndex, nNewStyle | TBBS_CHECKBOX);
  1503. }
  1504.  
  1505. void CToolCmdUI::SetText(LPCTSTR)
  1506. {
  1507.     // ignore it
  1508. }
  1509.  
  1510. void CToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
  1511. {
  1512.     CToolCmdUI state;
  1513.     state.m_pOther = this;
  1514.  
  1515.     state.m_nIndexMax = (UINT)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  1516.     for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
  1517.     {
  1518.         // get buttons state
  1519.         TBBUTTON button;
  1520.         _GetButton(state.m_nIndex, &button);
  1521.         state.m_nID = button.idCommand;
  1522.  
  1523.         // ignore separators
  1524.         if (!(button.fsStyle & TBSTYLE_SEP))
  1525.         {
  1526.             // allow reflections
  1527.             if (CWnd::OnCmdMsg(0, 
  1528.                 MAKELONG((int)CN_UPDATE_COMMAND_UI, WM_COMMAND+WM_REFLECT_BASE), 
  1529.                 &state, NULL))
  1530.                 continue;
  1531.  
  1532.             // allow the toolbar itself to have update handlers
  1533.             if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
  1534.                 continue;
  1535.  
  1536. #if defined(_WIN32_WCE)
  1537. // WinCE: Don't disable close adornment        
  1538.         if(m_pWndCommandBar != NULL)
  1539.         {
  1540.             if((button.idCommand == WM_HELP) || (button.idCommand == WM_CLOSE))
  1541.                 continue;
  1542.         }
  1543. #endif // _WIN32_WCE
  1544.             // allow the owner to process the update
  1545.             state.DoUpdate(pTarget, bDisableIfNoHndler);
  1546.         }
  1547.     }
  1548.  
  1549.     // update the dialog controls added to the toolbar
  1550.     UpdateDialogControls(pTarget, bDisableIfNoHndler);
  1551. }
  1552.  
  1553. /////////////////////////////////////////////////////////////////////////////
  1554. // CToolBar diagnostics
  1555.  
  1556. #ifdef _DEBUG
  1557. void CToolBar::AssertValid() const
  1558. {
  1559.     // Note: CControlBar::AssertValid is not called because it checks for
  1560.     //  m_nCount and m_pData to be in sync, which they are not in CToolBar.
  1561.  
  1562.     ASSERT(m_hbmImageWell == NULL ||
  1563.         (afxData.bWin95 || ::GetObjectType(m_hbmImageWell) == OBJ_BITMAP));
  1564.  
  1565.     if (m_hInstImageWell != NULL && m_hbmImageWell != NULL)
  1566.         ASSERT(m_hRsrcImageWell != NULL);
  1567. }
  1568.  
  1569. void CToolBar::Dump(CDumpContext& dc) const
  1570. {
  1571.     CControlBar::Dump(dc);
  1572.  
  1573.     dc << "m_hbmImageWell = " << (UINT)m_hbmImageWell;
  1574.     dc << "\nm_hInstImageWell = " << (UINT)m_hInstImageWell;
  1575.     dc << "\nm_hRsrcImageWell = " << (UINT)m_hRsrcImageWell;
  1576.     dc << "\nm_sizeButton = " << m_sizeButton;
  1577.     dc << "\nm_sizeImage = " << m_sizeImage;
  1578.  
  1579.     if (dc.GetDepth() > 0)
  1580.     {
  1581.         CToolBar* pBar = (CToolBar*)this;
  1582.         int nCount = pBar->DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  1583.         for (int i = 0; i < nCount; i++)
  1584.         {
  1585.             TBBUTTON button;
  1586.             _GetButton(i, &button);
  1587.             dc << "\ntoolbar button[" << i << "] = {";
  1588.             dc << "\n\tnID = " << button.idCommand;
  1589.             dc << "\n\tnStyle = " << MAKELONG(button.fsStyle, button.fsState);
  1590.             if (button.fsStyle & TBSTYLE_SEP)
  1591.                 dc << "\n\tiImage (separator width) = " << button.iBitmap;
  1592.             else
  1593.                 dc <<"\n\tiImage (bitmap image index) = " << button.iBitmap;
  1594.             dc << "\n}";
  1595.         }
  1596.     }
  1597.  
  1598.     dc << "\n";
  1599. }
  1600. #endif
  1601.  
  1602. #ifdef AFX_INIT_SEG
  1603. #pragma code_seg(AFX_INIT_SEG)
  1604. #endif
  1605.  
  1606. IMPLEMENT_DYNAMIC(CToolBar, CControlBar)
  1607.  
  1608. /////////////////////////////////////////////////////////////////////////////
  1609. #endif // _WIN32_WCE_NO_CONTROLBARS
  1610.